package com.cloudkinto.service.shipprice.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cloudkinto.common.web.SingleResult;
import com.cloudkinto.dao.*;
import com.cloudkinto.entity.*;
import com.cloudkinto.service.region.JpRegionService;
import com.cloudkinto.service.shipprice.DimensService;
import com.cloudkinto.service.shipprice.ShipPriceService;
import com.cloudkinto.service.shipprice.vo.ComputePriceReq;
import com.cloudkinto.service.shipprice.vo.ShipPriceRes;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * service实现类
 * </p>
 *
 * @author ding
 * @since 2020-06-09
 */
@Service
@Transactional(rollbackFor = Exception.class)//事务回滚
public class ShipPriceServiceImpl extends ServiceImpl<ShipPriceDao, ShipPriceDo> implements ShipPriceService {
    @Autowired
    private ShipPriceDao dao;
    @Autowired
    private StorageDao mStorageDao;
    @Autowired
    private DimensService mDimensService;
    @Autowired
    private JpRegionDao jpRegionDao;
    @Autowired
    private JpStateDao jpStateDao;
    @Autowired
    private DimensDao dimensDao;
    @Autowired
    private CompanyDao companyDao;
    @Autowired
    private StorageDao storageDao;
    @Autowired
    private DicBusinessItemDao dicBusinessItemDao;
    @Autowired
    private ProductInfoDao mProductDao;
    @Autowired
    private JpRegionService mRegionService;

    @Override
    public List<ShipPriceDo> queryByRegionAndSize(String postCode, double weight, double size, Long storageId, int version) {
        return queryByRegionAndSize(mRegionService.getStateIdByPostCode(postCode), weight, size, storageId, version);
    }

    /**
     * 根据 三边和/重量/  算运费
     *
     * @param stateId   所属地区
     * @param weight    重量
     * @param size      三边和
     * @param storageId 仓库id
     * @param version   费用版本
     * @return
     */
    @Override
    public List<ShipPriceDo> queryByRegionAndSize(Long stateId, double weight, double size, Long storageId, int version) {

        List<Long> dimensIds = new ArrayList<>();
        List<StorageDo> storageIds = new ArrayList<>();
        if (storageId == null || storageId == 0) {
            for (StorageDo storageBean :
                    storageIds) {
                dimensIds.addAll(mDimensService.listBySizeAndWeight(size, weight, storageBean.getId()));
            }
        } else {
            dimensIds.addAll(mDimensService.listBySizeAndWeight(size, weight, storageId));
        }

        if (dimensIds.size() < 1) {
            List<ShipPriceDo> shipPrices = new ArrayList<>();
            return shipPrices;
        }
        LambdaQueryWrapper<ShipPriceDo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ShipPriceDo::getStateId, stateId)
                .in(ShipPriceDo::getDimensId, dimensIds)
                .eq(ShipPriceDo::getActive, 1)
                .eq(ShipPriceDo::getVersion, version);
        List<ShipPriceDo> shipPrices = baseMapper.selectList(wrapper);
        if (shipPrices != null & shipPrices.size() > 0) {
            ShipPriceDo less = new ShipPriceDo();
            less.setPrice(99999D);
            for (ShipPriceDo ship : shipPrices) {
                if (ship.getPrice() < less.getPrice()) {
                    less = ship;
                }
            }
            shipPrices = new ArrayList<>();
            shipPrices.add(less);
        } else {
            wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(ShipPriceDo::getStateId, stateId)
                    .in(ShipPriceDo::getDimensId, dimensIds)
                    .eq(ShipPriceDo::getActive, 1)
                    .eq(ShipPriceDo::getVersion, 2);
            shipPrices = baseMapper.selectList(wrapper);
            if (shipPrices != null & shipPrices.size() > 1) {
                ShipPriceDo less = new ShipPriceDo();
                less.setPrice(99999D);
                for (ShipPriceDo ship : shipPrices) {
                    if (ship.getPrice() < less.getPrice()) {
                        less = ship;
                    }
                }
                shipPrices = new ArrayList<>();
                shipPrices.add(less);
            }
        }
        return shipPrices;
    }

    /**
     * 根据 三边和/重量/  算运费
     *
     * @param stateId   所属地区
     * @param weight    重量
     * @param size      三边和
     * @param storageId 仓库id
     * @param version   费用版本
     * @return
     */
    @Override
    public List<ShipPriceDo> queryByRegionAndSize(Long stateId, double weight, double size, Long storageId, Long trackId, int version) {

        List<Long> dimensIds = new ArrayList<>();
        List<StorageDo> storageIds = new ArrayList<>();
        if (storageId == null || storageId == 0) {
            for (StorageDo storageBean :
                    storageIds) {
                dimensIds.addAll(mDimensService.listBySizeAndWeight(size, weight, storageBean.getId(), trackId));
            }
        } else {
            dimensIds.addAll(mDimensService.listBySizeAndWeight(size, weight, storageId, trackId));
        }

        if (dimensIds.size() < 1) {
            List<ShipPriceDo> shipPrices = new ArrayList<>();
            return shipPrices;
        }
        LambdaQueryWrapper<ShipPriceDo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ShipPriceDo::getStateId, stateId)
                .in(ShipPriceDo::getDimensId, dimensIds)
                .eq(ShipPriceDo::getActive, 1)
                .eq(ShipPriceDo::getVersion, version);
        List<ShipPriceDo> shipPrices = baseMapper.selectList(wrapper);
        if (shipPrices != null & shipPrices.size() > 0) {
            ShipPriceDo less = new ShipPriceDo();
            less.setPrice(99999D);
            for (ShipPriceDo ship : shipPrices) {
                if (ship.getPrice() < less.getPrice()) {
                    less = ship;
                }
            }
            shipPrices = new ArrayList<>();
            shipPrices.add(less);
        } else {
            wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(ShipPriceDo::getStateId, stateId)
                    .in(ShipPriceDo::getDimensId, dimensIds)
                    .eq(ShipPriceDo::getActive, 1)
                    .eq(ShipPriceDo::getVersion, 2);
            shipPrices = baseMapper.selectList(wrapper);
            if (shipPrices != null & shipPrices.size() > 0) {
                ShipPriceDo less = new ShipPriceDo();
                less.setPrice(99999D);
                for (ShipPriceDo ship : shipPrices) {
                    if (ship.getPrice() < less.getPrice()) {
                        less = ship;
                    }
                }
                shipPrices = new ArrayList<>();
                shipPrices.add(less);
            }
        }
        return shipPrices;
    }

    @Override
    public SingleResult computePrice(ComputePriceReq req, Long userId, Long companyId) {
        ShipPriceRes res = new ShipPriceRes();

        CompanyDo companyDo = companyDao.selectById(companyId);

        StorageDo storageDo = storageDao.selectById(req.getStorageId());

        JpRegionDo jpRegionDo = jpRegionDao.selectById(req.getRegionId());

        Double volume = req.getHeight() * req.getLength() * req.getWidth();
        Double weight = req.getWidth();

        LambdaQueryWrapper<DimensDo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(DimensDo::getStorageId, req.getStorageId())
                .orderByAsc(DimensDo::getVolume)
                .orderByAsc(DimensDo::getWeight);
        List<DimensDo> dimensDoList = dimensDao.selectList(wrapper);

        //匹配算法
        Long volumeId = 0L;
        Long weightId = 0L;
        if (!CollectionUtils.isEmpty(dimensDoList)) {
            for (DimensDo dimensDo : dimensDoList) {
                if (volumeId != 0L && weightId != 0L) {
                    break;
                }
                if (dimensDo.getVolume() > volume) {
                    if (volumeId == 0) {
                        volumeId = dimensDo.getId();
                    }
                }
                if (dimensDo.getWeight() > weight) {
                    if (weightId == 0) {
                        weightId = dimensDo.getId();
                    }
                }
            }
        }
        Long dimensId = volumeId > weightId ? weightId : weightId;
        DimensDo dimensDo = dimensDao.selectById(dimensId);
        DicBusinessItemDo businessItemDo = dicBusinessItemDao.selectById(dimensDo.getTrackId());

        LambdaQueryWrapper<ShipPriceDo> priceWrapper = new LambdaQueryWrapper<>();
        priceWrapper.eq(ShipPriceDo::getStateId, jpRegionDo.getJpStateId())
                .eq(ShipPriceDo::getDimensId, dimensId)
                .eq(ShipPriceDo::getVersion, companyDo.getShipPriceVersion())
                .eq(ShipPriceDo::getActive, 1);
        List<ShipPriceDo> shipPriceDoList = dao.selectList(priceWrapper);

        if (!CollectionUtils.isEmpty(shipPriceDoList)) {
            res.setPrice(shipPriceDoList.get(0).getPrice());
            res.setStorage(storageDo.getStorageName());
            res.setTrackName(businessItemDo.getDicItemValue());
        }


        return SingleResult.success(res);
    }

    @Override
    public SingleResult computeInit() {
        Map result = new HashMap();

        List<Map> storageList = new ArrayList<>();
        List<StorageDo> storageDoList = storageDao.selectList(null);
        if (!CollectionUtils.isEmpty(storageDoList)) {
            storageDoList.forEach(storageDo -> {
                Map map = new HashMap();
                map.put("id", storageDo.getId());
                map.put("value", storageDo.getStorageName());
                storageList.add(map);
            });
        }
        result.put("storageList", storageList);

        List<Map> regionList = new ArrayList<>();
        List<JpRegionDo> regionDoList = jpRegionDao.selectList(null);
        if (!CollectionUtils.isEmpty(regionDoList)) {
            regionDoList.forEach(regionDo -> {
                Map map = new HashMap();
                map.put("id", regionDo.getId());
                map.put("value", regionDo.getName());
                regionList.add(map);
            });
        }
        result.put("regionList", regionList);
        return SingleResult.success(result);
    }


    /**
     * 计算多个不同sku
     *
     * @param packageDetail
     * @return float[]{最长边.次长边,短边和，重量}
     */
    @Override
    public double[] getMulitSkuSize(List<OrderOutputProductDo> packageDetail) {
        double[] finalSize = new double[4];
        if (packageDetail != null && packageDetail.size() > 0) {
            for (OrderOutputProductDo productDetail :
                    packageDetail) {
                finalSize = countSameSkuSize(finalSize, productDetail.getProductId(), productDetail.getCount());
            }
        }
        return finalSize;
    }

    /**
     * 获取多个SKu的操作费
     *
     * @param packageDetail
     * @param companyId
     * @return
     */
    @Override
    public int getMulitSkuOperationFee(List<OrderOutputProductDo> packageDetail, String companyId) {
        int fee = 0;
        if (packageDetail != null && packageDetail.size() > 0) {
            for (OrderOutputProductDo productDetail :
                    packageDetail) {
                fee += getSameSkuOperationFee(productDetail.getProductId(), productDetail.getCount(), companyId);
            }
        }
        return fee;
    }

    /**
     * 获取多个相同SKu的操作费
     *
     * @param productId
     * @param count
     * @param companyId
     * @return
     */
    @Override
    public int getSameSkuOperationFee(Long productId, int count, String companyId) {
        int fee = 0;
        ProductInfoDo productInfoDo = mProductDao.selectById(productId);
        float totalSize = productInfoDo.getWidth() + productInfoDo.getHeight() + productInfoDo.getLength();
        if (companyId.equals("C1030")) {
            fee = fee + 80 + (count - 1) * 50;
        } else if (totalSize < 60) {
            fee = fee + 100 + (count - 1) * 50;
        } else {
            fee = fee + 200 + (count - 1) * 100;
        }
        return fee;
    }

    /**
     * 计算单个相同sku
     *
     * @param productId
     * @param count
     * @return
     */
    @Override
    public double[] countSameSkuSize(Long productId, int count) {
        double[] finalSize = new double[4];
        QueryWrapper wrapper = new QueryWrapper();
        ProductInfoDo productBean = mProductDao.selectById(productId);
        double[] size = getSizeOrderDesc(productBean.getWidth()
                , productBean.getHeight(), productBean.getLength());
        finalSize[0] = size[0];
        finalSize[1] = size[1];
        finalSize[2] = size[2];
        //最短边相加
        if (finalSize[0] + finalSize[1] + finalSize[2] < 55 && finalSize[2] <= 3 && finalSize[0] <= 34) {
            finalSize[1] = finalSize[1] + size[1] * (count - 1);
        } else {
            finalSize[2] = finalSize[2] + size[2] * (count - 1);
        }
        finalSize[3] = finalSize[3] + productBean.getWeight() * count;
        return finalSize;
    }

    /**
     * 计算单个/多个相同sku
     *
     * @param finalSize
     * @param productId
     * @param count
     * @return
     */
    @Override
    public double[] countSameSkuSize(double[] finalSize, Long productId, int count) {
        finalSize = countSameSkuSizeNew(finalSize, productId, count);
        return finalSize;
    }

    /**
     * 计算单个/多个相同sku
     *
     * @param productId
     * @param count
     * @return
     */
    @Override
    public double[] countSameSkuSizeNew(double[] inputSize, Long productId, int count) {
        double[] outSizeSize = new double[4];
        ProductInfoDo productBean = mProductDao.selectById(productId);
        double[] size = getSizeOrderDesc(productBean.getWidth()
                , productBean.getHeight(), productBean.getLength());
        //最短边相加
        //如果最短边小于3，次短边相加小于34，次短边相加总边长小于55 ，则次短边相加
        if (((inputSize[0] > size[0] ? inputSize[0] : size[0]) + inputSize[1] + size[1] * count + (inputSize[2] > size[2] ? inputSize[2] : size[2]) < 55
                && inputSize[2] <= 3 && inputSize[0] <= 34 && inputSize[1] + size[1] * count <= 34) &&
                size[0] + size[1] + size[2] < 55 && size[2] <= 3 && size[0] <= 34) {
            outSizeSize[1] = inputSize[1] + size[1] * count;
        } else {
            outSizeSize[2] = inputSize[2] + size[2] * count;
        }
        for (int i = 0; i < size.length; i++) {
            if (outSizeSize[i] < size[i]) {
                outSizeSize[i] = size[i];
            }
        }
        outSizeSize[3] = inputSize[3] + productBean.getWeight() * count;
        return outSizeSize;
    }

    /**
     * 获取三边有大到小排序
     * * @param width
     *
     * @param height
     * @param length
     * @return
     */
    @Override
    public double[] getSizeOrderDesc(double width, double height, double length) {
        double[] floats = new double[]{width, height, length};
        for (int i = 0; i < floats.length; i++) {
            for (int j = 0; j < floats.length - i - 1; j++) {   // 这里说明为什么需要-1
                if (floats[j] < floats[j + 1]) {
                    double temp = floats[j];
                    floats[j] = floats[j + 1];
                    floats[j + 1] = temp;
                }
            }
        }
        return floats;
    }

}
